<template>
  <el-form
      v-bind="$attrs"
      :inline="search"
      :label-suffix="labelSuffix"
      ref="formRef"
      :label-width="labelWidth"
      scroll-to-error
      @keyup.enter="enterUp"
      :model="modelValue">
    <slot name="configBefore"></slot>
    <template v-if="search">
      <template v-for="(item,index) in formConfigList">
        <FromItem
            v-if="__hiddenFunc(item)"
            :key="'com'+index"
            :item="item"
            ref="components"
            :form-vm="self"
            :form-data="modelValue"
        ></FromItem>
      </template>
    </template>
    <template v-else>
      <el-row
        v-for="(row,index) in rowList"
        :key="'row'+index"
        :gutter="gutter"
      >
        <el-col
          v-for="(col,ind) in row"
          :key="index+'col'+ind"
          :span="formConfigList[col].span || span"
        >
          <FromItem
              class="formItemForm"
              :item="formConfigList[col]"
              ref="components"
              :form-vm="self"
              :form-data="modelValue"
          ></FromItem>
        </el-col>
      </el-row>
    </template>
    <slot></slot>
  </el-form>
</template>

<script lang="ts">
import {PropType,defineComponent} from "vue";
import {FormConfigItem} from "./types";
import FromItem from "./FromItem.vue";
import {FormItemProp} from "element-plus";
import {Arrayable} from "@vueuse/core";
import typeOfUtils from "../../utils/type-of-utils";

export default defineComponent({
  name: "DynamicForm",
  components: {FromItem},
  emits:['search'],
  props:{
    modelValue: {
      type: Object,
      default: {}
    },
    search: {
      type: Boolean,
      default: false
    },
    formConfigList: {
      type:Array as PropType<FormConfigItem[]>,
      default: []
    },
    span: {
      type: Number,
      default: 24,
    },
    gutter: {
      type: Number,
      default: 0,
    },
    labelSuffix: {
      type: String,
      default: '',
    },
    labelWidth: {
      type: String,
      default: 'auto',
    },
    createdInitValue: { // 创建组件的时候初始化组件数据
      type: Boolean,
      default: true
    },
    createdHasInitValueNotInit: { // 创建组件的时候如果有值不初始化组件数据
      type: Boolean,
      default: false
    },
    inputSearchWidth: { // 在search的时候input的宽度
      type: String,
      default: '240px'
    }
  },
  computed:{
    self() {
      return this
    },
    rowList() { // 计算布局 el-row el-col
      /**
       * 采用数组套数组的形式，数组里面存放formConfigList的下标
       */
      let result = []
      let count = 0
      let items = []
      this.formConfigList.forEach((item,index)=>{
        if(!this.__hiddenFunc(item)){
          return
        }
        count+=(item.span || this.span)
        if(count<=24){
          items.push(index)
        } else {
          count=item.span || this.span
          result.push(items)
          items=[index]
        }
      })
      if(items.length){
        result.push(items)
      }
      return result
    }
  },
  data(){
    return{
    }
  },
  methods: {
    __hiddenFunc(item: FormConfigItem) {
      // 支持hidden为函数
      // @ts-ignore
      if(typeOfUtils.isFunction(item.hidden)) {
        // @ts-ignore
        return !item.hidden(item)
      }
      return !(item.hidden || false)
    },
    enterUp() {
      if(this.search){
        this.$emit('search')
      }
    },
    /**
     * 采用异步，避免清楚不完整
     */
    resetFields() {
      return new Promise((resolve,reject) => {
        setTimeout(()=>{
          Promise.all(
            this.$refs.components.map(i=>i.resetField())
          ).then(()=>{
            setTimeout(()=>{
              this.clearValidate()
              resolve()
            })
          }).catch(reject)
        })
      })
    },
    clearValidate(props?: Arrayable<FormItemProp> | undefined){
      this.$refs.formRef.clearValidate(props)
    },
    validate() {
      return this.$refs.formRef.validate()
    },
    validateField(fields:string[]=[]) {
      return this.$refs.formRef.validateField(fields)
    },
    scrollToField(field:string) {
      return this.$refs.formRef.scrollToField(field)
    },
  }
})
</script>

<style scoped lang="scss">
.formItemForm{
  ::v-deep{
    .el-select{
      width: 100%;
    }
  }
}
</style>
